<?php
class Pageley_Domain_Attribute_ManyToManyDecorator extends Pageley_Domain_Attribute_MultipleDecorator {
    private $relationType;
    private $referencingType;
    private $dependent;
    
    public function __construct($attribute, $referencingType, $dependent = false) {
        $validators = new Pageley_Util_ArrayMap();
        if(!($attribute instanceof Pageley_Domain_Attribute_Reference)) {
            throw new Pageley_Domain_RuntimeException("Only reference attributes are supported in many-to-many relationships.");
        }
        parent::__construct($attribute, $validators);
        $this->referencingType = $referencingType;
        $this->dependent = $dependent;
    }

    public function isManyToMany() {
        return true;
    }
    
    public function getRelationType() {
        if($this->relationType === null) {
            $this->relationType = $this->retrieveRelationType($this->referencingType, $this->getDecoratedAttribute()->getType());
        }
        return $this->relationType;
    }
    
    private function retrieveRelationType($referencingType, $referencedType) {
        $pon = Pageley_Config::getInstance();
        $configId = "type." . $referencingType->getFullName() . $referencedType->getName();
        $relationType = null;
        try {
            $relationType = $relationType = $pon->valueOf($configId);
        } catch(Pageley_Config_Exception $e) {
            $configId = "type." . $referencedType->getFullName() . $referencingType->getName();
            try {
                $relationType = $pon->valueOf($configId);
            } catch(Pageley_Config_Exception $e) {
                $relationType = $this->createRelationType($referencingType, $referencedType);
            }
        }
        return $relationType;
    }
    
    private function createRelationType($referencingType, $referencedType) {
        $pon = Pageley_Config::getInstance();
        $lengthValidator = new Pageley_Domain_Validator_Length();
        $lengthValidator->setMaxLength(32);
        $propertyNameAttribute = new Pageley_Domain_Attribute_Basic("propertyName", new Pageley_Util_ArrayMap($lengthValidator));
        $referencingTypeName = $referencingType->getName();
        $referencedTypeName = $referencedType->getName();
        $referencingTypeAttribute = new Pageley_Domain_Attribute_Reference($referencingTypeName, $referencingType);
        $referencedTypeAttribute = new Pageley_Domain_Attribute_Reference($referencedTypeName, $referencedType);
        $relationType = new Pageley_Domain_BasicType(
                $referencingType->getNamespace(),
                $referencingTypeName . $referencedTypeName,
                new Pageley_Util_ArrayMap(array(
                    $referencingTypeName . "PropertyName" => new Pageley_Domain_Attribute_RequiredDecorator($propertyNameAttribute),
                    $referencedTypeName . "PropertyName" => $propertyNameAttribute,
                    $referencingTypeName => new Pageley_Domain_Attribute_RequiredDecorator($referencingTypeAttribute),
                    $referencedTypeName => new Pageley_Domain_Attribute_RequiredDecorator($referencedTypeAttribute)
                )));
        $configId = "type." . $referencingType->getFullName() . $referencedType->getName();
        $pon->addReference($configId, $relationType);
        return $relationType;
    }
    
    public function __toString() {
        return $this->getName() . "(many to many)";
    }             
}